﻿using System;
using System.Collections.Generic;
using System.Disposables;
using System.Linq;
using System.Windows.Threading;
using SoftSource.Reactive;
using SoftSource.Timecard.Web.Data;
using SoftSource.Timecard.Web.Services;

namespace SoftSource.Timecard.Model
{
    public sealed partial class ProjectManagerModel : IModel
    {
        #region Fields
        private CompositeDisposable compositeDisposable;
        private Dispatcher dispatcher;

        private UtilityContext utilities;
        private EntryContext entries;
        private StaticContext staticTypes;
        private ReadOnlyContext readOnlyTypes;
        #endregion Fields

        public ProjectManagerModel(Dispatcher dispatcher)
        {
            this.dispatcher = dispatcher;
            this.compositeDisposable = new CompositeDisposable();

            InitializeContexts();
            InitializeEntityWrappers();

            List<IObservable<Unit>> load = new List<IObservable<Unit>>();
            load.Add(this.LoadStaticTypes());
            load.Add(this.LoadReadOnlyTypes());

            this.PreLoadQuery = load.ForkJoin().Once();
        }

        #region Initialization
        private void InitializeContexts()
        {
            this.utilities = new UtilityContext();
            this.entries = new EntryContext();
            this.staticTypes = new StaticContext();
            this.readOnlyTypes = new ReadOnlyContext();
        }
        #endregion Initialization

        #region Data Load
        private IObservable<Unit> LoadStaticTypes()
        {
            // Static types
            return Observable.ForkJoin(
                this.Roles.Load,
                this.Reports.Load,
                this.UserTypes.Load,
                this.ProjectTypes.Load,
                this.RevenueTypes.Load,
                this.BillingStates.Load,
                this.ProjectStatuses.Load,
                this.BillingFrequencies.Load)
                .ToUnit();
        }

        private IObservable<Unit> LoadReadOnlyTypes()
        {
            // Read-Only types
            return Observable.ForkJoin(
                this.UserSummaries.Load,
                this.ProjectSummaries.Load,
                this.CategorySummaries.Load)
                .ToUnit();
        }
        #endregion Data Load

        #region Set Resources
        private void SetResources()
        {
            var managers = this.readOnlyTypes.UserSummaries.Where(us => us.IsActive && (us.RoleID == Role.Administrator || us.RoleID == Role.ProjectManager));

            this.SetResource("Managers", managers);

            this.SetStaticResources();
            this.SetReadOnlyResources();
        }

        private void SetStaticResources()
        {
            //Static Types
            this.SetResource("Roles", this.staticTypes.Roles);
            this.SetResource("UserTypes", this.staticTypes.UserTypes);
            this.SetResource("ProjectTypes", this.staticTypes.ProjectTypes);
            this.SetResource("RevenueTypes", this.staticTypes.RevenueTypes);
            this.SetResource("ProjectStatuses", this.staticTypes.ProjectStatus);
            this.SetResource("BillingStates", this.staticTypes.BillingStates);
            this.SetResource("BillingFrequencies", this.staticTypes.BillingFrequencies);
        }

        private void SetReadOnlyResources()
        {
            //Read-Only Types
            this.SetResource("UserSummaries", this.readOnlyTypes.UserSummaries);
            this.SetResource("ProjectSummaries", this.readOnlyTypes.ProjectSummaries);
            this.SetResource("CategorySummaries", this.readOnlyTypes.CategorySummaries);
            this.SetResource("CustomerSummaries", this.readOnlyTypes.CustomerSummaries);
            this.SetResource("MilestoneSummaries", this.readOnlyTypes.MilestoneSummaries);
            this.SetResource("CustomerUserSummaries", this.readOnlyTypes.CustomerUserSummaries);
            this.SetResource("ProjectMemberSummaries", this.readOnlyTypes.ProjectMemberSummaries);
            this.SetResource("ProjectCategorySummaries", this.readOnlyTypes.ProjectCategorySummaries);
            this.SetResource("CustomerProjectSummaries", this.readOnlyTypes.CustomerProjectSummaries);
        }

        private void SetResource(string key, object value)
        {
            this.dispatcher.BeginInvoke(() =>
                {
                    if (App.Current.Resources[key] != null)
                        App.Current.Resources.Remove(key);
                    App.Current.Resources.Add(key, value);
                });
        }
        #endregion Set Resources

        #region Load Queries
        private IObservable<Unit> PreLoadQuery { get; set; }
        #endregion Load Queries

        #region IDisposable Members

        public void Dispose()
        {
            this.compositeDisposable.Dispose();
            GC.SuppressFinalize(this);
        }

        #endregion

        ~ProjectManagerModel()
        {
            this.Dispose();
        }
    }
}
